# 在user经过login之后，根据生成的token认证通过了后，才能到order里面来进行后续的操作
import datetime

from flask import g
from flask_restful import Resource, reqparse, abort, fields, marshal
# from App.apis.movie_user.model_utils import get_user
# from App.ext import cache
from sqlalchemy import or_

from App.apis.api_constant import HTTP_OK
from App.apis.movie_user.utils import login_required, is_token, required_permission
from App.ext import db
from App.models.cinema_admin.cinema_hall_model import Hall
from App.models.cinema_admin.cinema_hall_movie_model import HallMovie
from App.models.movie_user.movie_order_model import MovieOrder, ORDER_STATUS_NOT_PAY, ORDER_STATUS_PAID_BUT_NOT_GET, \
    ORDER_STATUS_GET
from App.models.movie_user.movie_user_model import VIP_USER
# parse = reqparse.RequestParser()
# parse.add_argument("token" , required = True , help = "请登录")

parse = reqparse.RequestParser()
parse.add_argument("hall_movie_id" , required = True ,type = int ,  help = "请提供排挡信息")
parse.add_argument("o_seats" , required = True , help = "请正确选择座位")

movie_order_fields = {
    "o_price":fields.Integer,
    "o_seats":fields.String,
    "o_hall_movie_id":fields.Integer,
}

class MovieOrdersResource(Resource):
    @login_required     # 方案一，使用装饰器来实现复用代码的目的，把对token的验证封装起来
    def post(self):
        # args = parse.parse_args()      垃圾 。改用装饰器。里面就直接写登录后的操作了
        #
        # token = args.get("token")
        # user_id = cache.get(token)
        # user = get_user(user_id)
        # if not user:
        #     abort(401 , msg = "请提供有效令牌")

        # user = is_token()     # 这个是方案二，封装函数的形式，跟现在用的装饰器一样能实现目的（使用这个时，不需要用到全局变量）

        user = g.user
        # print(user.username)

        args = parse.parse_args()
        hall_movie_id = args.get("hall_movie_id")
        o_seats = args.get("o_seats")

        movie_orders_paid = MovieOrder.query.filter(MovieOrder.o_hall_movie_id == hall_movie_id).filter(or_(MovieOrder.o_status == ORDER_STATUS_PAID_BUT_NOT_GET , MovieOrder.o_status == ORDER_STATUS_GET)).all()
        movie_orders_lock = MovieOrder.query.filter(MovieOrder.o_hall_movie_id == hall_movie_id).filter(MovieOrder.o_status == ORDER_STATUS_NOT_PAY).filter(MovieOrder.o_time > datetime.datetime.now()).all()

        seats = []      # 里面存的是已经卖了的和已经锁单了的
        for movie_orders in movie_orders_paid:
            sold_seats = movie_orders.o_seats.split("#")
            # seats.append(sold_seats)      # 这样加，列表里都是列表，转set就转不回list。不能list不可哈希的元素
            seats += sold_seats     # 这样加，列表里面就不会有列表
        for movie_orders in movie_orders_lock:
            sold_seats = movie_orders.o_seats.split("#")
            # seats.append(sold_seats)
            seats += sold_seats

        hall_movie = HallMovie.query.get(hall_movie_id)
        hall = Hall.query.get(hall_movie.h_hall_id)
        all_seats = hall.h_seats.split("#")
        can_pay = list(set(all_seats) - set(seats))

        want_buy = o_seats.split("#")
        print(want_buy , can_pay)
        for item in want_buy:
            if item not in can_pay:
                abort(400 , msg = '锁座失败，不可购买，请选择其他座位')

        movie_order = MovieOrder(o_hall_movie_id = hall_movie_id , o_seats = o_seats , o_user_id = user.id)
        movie_order.o_time = datetime.datetime.now() + datetime.timedelta(minutes=15)

        # # 悲观加锁
        # db.session.with_lockmode("update")
        # 针对此次操作加锁
        # db.session.Query(MovieOrder).with_lockmode("update")
        # db.session.commit()

        # 事务
        # db.session.rollback()



        if not movie_order.save():
            abort(400 , msg = '下单失败')
        data = {
            "msg":"success",
            "status":HTTP_OK,
            "data":marshal(movie_order , movie_order_fields)
        }

        return data

class MovieOrderResource(Resource):
    # 修改订单的话用这个。暂时还没内容，壳子先搭好了。
    @required_permission(permission = VIP_USER)         # 这里也是用了装饰器，对用户token进行验证的前提下，还对用户的权限进行认证。但这是带参的装饰器，要多包一层
    def put(self , order_id):
        # user = g.user         # 垃圾代码，封装起来。达到一进来就是写核心逻辑，不要在里面判断一大堆的目的。
        # if not user.check_permission(VIP_USER):
        #     abort(403 , msg = '没有修改权限')


        return {"msg" : "修改成功"}



